package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.constants.WmNewsMessageConstants;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.UpOrDownMess;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    WmMaterialMapper wmMaterialMapper;

    @Override
    public ResponseResult list(WmNewsPageReqDto dto) {
        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        WmUser user = WmThreadLocalUtil.getUser();
        if(user==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //2.分页条件查询
        IPage<WmNews> pageParam = new Page<>(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        if(dto.getStatus()!=null){
            wrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        if(StringUtils.isNotBlank(dto.getKeyword())){
            wrapper.like(WmNews::getTitle, dto.getKeyword());//模糊查询
        }
        if(dto.getChannelId()!=null){
            wrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        if(dto.getBeginPubDate()!=null &&dto.getEndPubDate()!=null){
            wrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());//区间查询
        }
        //只能查询自己的文章
        wrapper.eq(WmNews::getUserId, user.getId());
        //按文章发布时间倒序
        wrapper.orderByDesc(WmNews::getPublishTime);


        IPage<WmNews> page = this.page(pageParam, wrapper);


        //3.封装结果返回
        PageResponseResult pageResponseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        pageResponseResult.setData(page.getRecords());

        return pageResponseResult;
    }


    @Autowired
    WmNewsAutoScanService wmNewsAutoScanService;

    @Override
    @Transactional//事务
    public ResponseResult submit(WmNewsDto dto) {
        //文章发布  线程名字 http-nio-51803-exec-8  WmNewsDto参数 WmNewsDto(id=null, title=测试文章标题06, channelId=1, labels=测试文章标题06, publishTime=Wed Mar 01 14:17:03 CST 2023, content=[{"type":"text","value":"测试文章标题06测试文章标题06测试文章标题06"},{"type":"image","value":"http://192.168.200.130:9000/leadnews/2023/02/27/6d523d8a746945db9ef6d47ed096f94e.jpeg"},{"type":"text","value":"请在这里输入正文"}], type=-1, submitedTime=null, status=1, images=[], enable=null)
        log.info("文章发布  线程名字 {}  WmNewsDto参数 {}", Thread.currentThread().getName(), dto);

        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(StringUtils.isBlank(dto.getTitle())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmUser user = WmThreadLocalUtil.getUser();
        if(user==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        if(StringUtils.isBlank(dto.getContent())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //其他参数校验


        //2.创建WmNews实体类，接受WmNewsDto参数
        WmNews wmNews = new WmNews();


        HashSet<String> urls = new HashSet<>();//去重    内容中图片的 路径集合
        String content = dto.getContent();//将content转为集合对象 遍历
        List<Map> list = JSON.parseArray(content, Map.class);
        for (Map map : list) {
            if(map.get("type").equals("image")){
                String imgUrl  = (String)map.get("value");
                if(StringUtils.isNotBlank(imgUrl)){
                    urls.add(imgUrl);
                }
            }
        }
        //3.自动选择封面处理  type是不是-1   (0 无图  1单图  3多图   自动-1)
        List<String> listUrls = new ArrayList<>(urls);
        if(dto.getType()!=null && dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            int size = urls.size();//内容中 图片的数量
            if(size>=3){
                List<String> strings = listUrls.subList(0, 3);//取3张图片作为封面图片
                //stream 流
//                List<String> strings = urls.stream().limit(3).collect(Collectors.toList());
                dto.setImages(strings);
                dto.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            }else if(size>=1){
                List<String> strings = listUrls.subList(0, 1);//取1张图片作为封面图片
                dto.setImages(strings);
                dto.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            }else{
                dto.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }
        }

        BeanUtils.copyProperties(dto, wmNews);
        //images需要特殊处理
        if(dto.getImages()!=null && dto.getImages().size()>0){
            wmNews.setImages(StringUtils.join(dto.getImages(), ","));
            //http://192.168.200.130:9000/leadnews/2021/4/20210418/7d0911a41a3745efa8509a87f234813c.jpg,http://192.168.200.130:9000/leadnews/2021/4/20210418/7d0911a41a3745efa8509a87f234813c.jpg
        }


        //4.判断是否携带id （有id则先删除文章和素材的对应关系后修改，无id则新增）
        wmNews.setSubmitedTime(new Date());
        if(dto.getId()!=null){
            //修改   先删除文章和素材的对应关系后修改
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            this.updateById(wmNews);
        }else{
            //给属性赋默认值
            wmNews.setCreatedTime(new Date());
            wmNews.setUserId(user.getId());
            wmNews.setEnable((short)1);
            //新增
            this.save(wmNews);
        }

        //5.判断是否是草稿 （如果是草稿直接返回）
        if(dto.getStatus()!=null && dto.getStatus().equals(WmNews.Status.NORMAL.getCode())){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        //6.保存文章和内容中图片的关联关系， 保存文章和封面中的图片的关联关系
        saveNewsAndMaterialRelation(wmNews.getId(), listUrls, WemediaConstants.WM_CONTENT_REFERENCE);//保存文章和内容中图片的关系
        saveNewsAndMaterialRelation(wmNews.getId(), dto.getImages(), WemediaConstants.WM_COVER_REFERENCE);//保存文章和封面中图片的关系


        //发布完文章后,开启新线程异步的审核文章
        wmNewsAutoScanService.autoScan(wmNews.getId());

        //7.返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存文章和内容中图片关联关系
     * 保存文章和封面中图片关联关系
     * @param newsId  文章id
     * @param images  内容中图片的路径集合     或者   封面中图片路径的集合
     * @param wmCoverReference  0代表内容    1代表封面
     */
    private void saveNewsAndMaterialRelation(Integer newsId, List<String> images, Short wmCoverReference) {
        //1.校验
        if(images==null || images.size()==0){
            return ;
        }
        //2.根据images 图片路径集合  查询素材表wm_material 获取该图片路径对应的  id
        //select * from wm_material where url in( xxxx, xxx, xxxx)
        List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, images));
        //遍历wmMaterials拿到素材的id集合
//        List<Integer> ids = new ArrayList<>();
//        for (WmMaterial wmMaterial : wmMaterials) {
//            ids.add(wmMaterial.getId());
//        }
        //stream
        List<Integer> ids = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());

        if(ids==null || ids.size()==0 || ids.size()!=images.size()){
            //说明有部分图片失效  或者被删除了
            throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
        }

        //3.将图片id集合 保存到中间表wm_news_material    批量保存
        wmNewsMaterialMapper.saveRelation(ids, newsId, wmCoverReference);
    }

    @Autowired
    WmNewsMapper wmNewsMapper;
    @Autowired
    KafkaTemplate<String, String> kafkaTemplate;

    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1.校验
        if(dto==null || dto.getId()==null || dto.getEnable()==null ){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = wmNewsMapper.selectById(dto.getId());
        if(wmNews==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            //说明文章状态不是  已发布
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章状态不是已发布，不允许操作上下架");
        }
        if(dto.getEnable()>1 || dto.getEnable()<0){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.修改文章wm_news表enable字段   0下架    1上架
        wmNews.setEnable(dto.getEnable());
        wmNewsMapper.updateById(wmNews);


        //3.发送消息到kafka    主题是wm.news.up.or.down.topic
        UpOrDownMess orDownMess = new UpOrDownMess();
        orDownMess.setArticleId(wmNews.getArticleId());
        orDownMess.setEnable(dto.getEnable());
        String msg = JSON.toJSONString(orDownMess);
        log.info("上下架发送消息到kafka   内容: {}", msg);
        kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, msg);

        //4.返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}
